package com.bangdao.hu.roomba.WifiSignalStrengthMap;

import android.app.Activity;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.net.wifi.WifiManager;

import com.bangdao.hu.roomba.Robot;

public class MapGenerator {
	// Robot scan the floor plan of level 4 from origin(0,0)
	// every 5 seconds sense wifi strength and current position
	// gather data as (x, y): {[BSSID: strength] [BSSID: strength] [BSSID: strength] [BSSID: strength] [BSSID: strength] [BSSID: strength]} 
	// what data structure used to store?
	// ArrayList What do you think?
	
	//wifi strength ===> list
//	private Robot robot; 
	
	private static ArrayList<MapPoint> signalMap;
//	HashMap<String, Integer> wifiMap;

//	private WifiManager wifi;
	private static MapGenerator instance = null;
	private static int MapPointCount = 0;
	
    protected MapGenerator() {
    	signalMap = new ArrayList<MapPoint>();
//    	wifiMap = new HashMap<String, Integer>();
//    	robot = new Robot();
     }
    
    public static MapGenerator getInstance() {
      if(instance == null) {
         instance = new MapGenerator();
      }
      return instance;
    }

	public void generateMap()
	{
//		wifiMap.put("dd:34:db:55", -78.9999);
//		wifiMap.put("dd:34:da:55", -78.9999);
//		wifiMap.put("dd:34:dd:55", -78.9999);
//		wifiMap.put("dd:34:ec:55", -78.9999);
//		wifiMap.put("dd:34:df:55", -78.9999);
//		double[] point = {3.4, 67};
//		signalMainMap.put(point, wifiMap);

		//Generate Graphic Map Here

	}
	
	

	public void robotScan()
	{
		//robot.getController()
		
		
	}

	public void putPoint (MapPoint currentPoint){
		signalMap.add(currentPoint);
		MapPointCount ++;
		System.out.println("*****MAP POINT COUNT is " + MapPointCount);
	}
	
	
	public MapPoint getPointMap(int x, int y)
	{
//		for(MapPoint mp:signalMap)
//		{
//			if(mp.isCurrentPoint(x,y))
//			{
//				System.out.println("got point!!!");
//				System.out.println("MP is " + mp);
//				return mp;
//			}
//		}
		//MapPoint mp = null;
		for(int i = 0; i<signalMap.size(); i++)
		{
			if(signalMap.get(i).isCurrentPoint(x, y))
			{
				return signalMap.get(i);
			}
		}
		return null;
	}
	
	public int getPointMapIndex(int x, int y)
	{
		for(int i = 0; i<signalMap.size(); i++)
		{
			if(signalMap.get(i).isCurrentPoint(x, y))
			{
				System.out.println("Index is " + i);
				return i;
			}
		}
		return -1;
	}
	
	
	private MapPoint rebuildPointMap(int[] cords, MapPoint[] points, double[] ratios)
	{
		HashMap<String, Integer> map = new HashMap<String, Integer>();  
		
		for(String key: map.keySet())
		{
			map.put(key, (int)(map.get(key)*ratios[0]));
		}
		
		for(int i = 1; i < points.length; i++)
		{
			for(String key: map.keySet())
			{
				map.put(key, (int)(map.get(key)+points[i].getWifiID().get(key)*ratios[i]));
			}
		}
		
		MapPoint newMapPoint = new MapPoint(cords, map);
		
		return newMapPoint;
	}
	
	public MapPoint getPoint(int x, int y)
	{
		int[] cords = {x, y};
		if((x%1000 == 0) && (y%1000 == 0)) //exact point 
		{
			return getPointMap(x,y);			
		}else if(x%1000 == 0)
		{
			//A(x, y/1000*1000)
			//C(x, y/1000*1000 - 1000)		
			MapPoint point1 = getPointMap(x, y/1000*1000);
			if(point1 == null)
			{
				return null;
			}
			MapPoint point2 = getPointMap(x, y/1000*1000 - 1000);
			if(point2 == null)
			{
				return null;
			}
			double point1Ratio = -1*y%1000/1000;
			double point2Ratio = 1-point1Ratio;
			MapPoint[] maps = {point1, point2};
			double[] ratios = {point1Ratio, point2Ratio};
			
			MapPoint combined = rebuildPointMap(cords, maps, ratios);
			
			return combined;
		}else if(y%1000 == 0)
		{
			//A(x/1000*1000,y)
			//B(x/1000*1000 + 1000,y)
			MapPoint point1 = getPointMap(x/1000*1000,y);
			if(point1 == null)
			{
				return null;
			}
			MapPoint point2 = getPointMap(x/1000*1000 + 1000,y);
			if(point2 == null)
			{
				return null;
			}
			double point1Ratio = -1*y%1000/1000;
			double point2Ratio = 1-point1Ratio;
			MapPoint[] maps = {point1, point2};
			double[] ratios = {point1Ratio, point2Ratio};
			
			MapPoint combined = rebuildPointMap(cords, maps, ratios);
			return combined;
			
		}else{
			//A(x/1000*1000, y/1000*1000)
			//B(x/1000*1000 + 1000, y/1000*1000)
			//C(x/1000*1000, y/1000*1000 - 1000)
			//D(x/1000*1000 + 1000, y/1000*1000 - 1000)
			int x1 = x/1000*1000;
			int y1 = y/1000*1000;
			int x2 = x1 + 1000;
			int y2 = y1;
			int x3 = x1;
			int y3 = y1 - 1000;
			int x4 = x1 + 1000;
			int y4 = y1 - 1000;
			MapPoint point1 = getPointMap(x1, y1);
			if(point1 == null)
			{
				return null;
			}
			MapPoint point2 = getPointMap(x2, y2);
			if(point2 == null)
			{
				return null;
			}
			MapPoint point3 = getPointMap(x3, y3);
			if(point3 == null)
			{
				return null;
			}
			MapPoint point4 = getPointMap(x4, y4);
			if(point4 == null)
			{
				return null;
			}
			
			double distance1 = getDistance(x,y,x1, y1);
			double distance2 = getDistance(x,y,x2, y2);
			double distance3 = getDistance(x,y,x3, y3);
			double distance4 = getDistance(x,y,x4, y4);
			double sum = distance1 + distance2 + distance3 + distance4;
			double point1Ratio = distance1 / sum;
			double point2Ratio = distance2 / sum;
			double point3Ratio = distance3 / sum;
			double point4Ratio = distance4 / sum;
			
			MapPoint[] maps = {point1, point2, point3, point4};
			double[] ratios = {point1Ratio, point2Ratio,point3Ratio, point4Ratio };
			
			MapPoint combined = rebuildPointMap(cords, maps, ratios);
			return combined;
		}
	}
	
	
	private double getDistance(int x1, int y1, int x2, int y2)
	{
		return Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2));
	}
	
	public ArrayList<MapPoint> getMap()
	{
		return signalMap;
	}
}
